package com.haiyou.dc.netty.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.haiyou.common.base.AbstractBaseService;
import com.haiyou.common.constant.MsgCode;
import com.haiyou.common.exception.BusinessException;
import com.haiyou.common.util.IdWorker;
import com.haiyou.dc.netty.chat.Message;
import com.haiyou.dc.netty.constant.ImChatConstant;
import com.haiyou.dc.netty.constant.RedisConstant;
import com.haiyou.dc.netty.entity.ImChat;
import com.haiyou.dc.netty.entity.ImUser;
import com.haiyou.dc.netty.entity.dto.ImChatDTO;
import com.haiyou.dc.netty.entity.dto.ImChatListDTO;
import com.haiyou.dc.netty.entity.vo.ImChatVO;
import com.haiyou.dc.netty.mapper.ImChatMapper;
import com.haiyou.dc.netty.service.ImChatService;
import com.haiyou.dc.netty.service.ImUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

/**
 * @author root
 * @date 2020-02-29 22:49:56
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class ImChatServiceImpl extends AbstractBaseService<ImChatMapper, ImChat> implements ImChatService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private ImUserService imUserService;

    @Override
    public ImChat saveChat(ImChatDTO imChatDTO) {

        ImChat imChat = new ImChat();
        BeanUtils.copyProperties(imChatDTO, imChat);
        imChat.setCreateTime(new Date());

        String body = JSON.toJSONString(imChat);

        //发送发送者
        imChat.setId(IdWorker.getId());
        imChat.setBody(body);
        this.insertSelective(imChat);

        //最近发送者联系人
        String senderKey = RedisConstant.getRecentUserKey(imChatDTO.getSender());
        String senderMsgKey = RedisConstant.getRecentMsgKey(imChatDTO.getSender(), imChatDTO.getReceiver());
        redisTemplate.opsForList().remove(senderKey, 0, imChatDTO.getReceiver());
        redisTemplate.opsForList().leftPush(senderKey, imChatDTO.getReceiver());
        Map<String, String> hashMap = new HashMap<>();
        hashMap.put(RedisConstant.RECENT_MSG_ID_KEY, imChat.getId());
        hashMap.put(RedisConstant.RECENT_RECEIVER_KEY, JSON.toJSONString(imUserService.selectByPrimaryKey(imChatDTO.getReceiver())));
        redisTemplate.opsForHash().putAll(senderMsgKey, hashMap);

        //最近接收者联系人
        String receiverKey = RedisConstant.getRecentUserKey(imChatDTO.getReceiver());
        String receiverMsgKey = RedisConstant.getRecentMsgKey(imChatDTO.getReceiver(), imChatDTO.getSender());
        redisTemplate.opsForList().remove(receiverKey, 0, imChatDTO.getSender());
        redisTemplate.opsForList().leftPush(receiverKey, imChatDTO.getSender());

        hashMap.put(RedisConstant.RECENT_MSG_ID_KEY, imChat.getId());
        hashMap.put(RedisConstant.RECENT_RECEIVER_KEY, JSON.toJSONString(imUserService.selectByPrimaryKey(imChatDTO.getSender())));
        redisTemplate.opsForHash().putAll(receiverMsgKey, hashMap);

        return this.selectByPrimaryKey(imChat.getId());

    }

    @Override
    public ImChat listenerMessage(Message message) {
        ImChatDTO imChatDTO = new ImChatDTO();
        BeanUtils.copyProperties(message, imChatDTO);
        return this.saveChat(imChatDTO);
    }

    @Override
    public Map<String, Object> selectMessage(String sender) {
        String senderKey = RedisConstant.getRecentUserKey(sender);
        List<String> receiverIds = redisTemplate.opsForList().range(senderKey, 0, -1);

        Integer totalUnRead = 0;
        Map<String, Object> result = new HashMap<>();
        if (receiverIds == null || receiverIds.size() <= 0) {
            result.put("totalUnRead", totalUnRead);
            result.put("data", Lists.newArrayList());
            return result;
        }
        HashOperations<String, Object, Object> opsForHash = redisTemplate.opsForHash();
        List<Object> msgIds = new ArrayList<>();
        for (String userId : receiverIds) {
            String senderMsgKey = RedisConstant.getRecentMsgKey(sender, userId);
            msgIds.add(opsForHash.get(senderMsgKey, RedisConstant.RECENT_MSG_ID_KEY));
        }

        Example example = new Example(ImChat.class);
        example.orderBy("createTime").desc();
        example.createCriteria().andIn("id", msgIds);
        List<ImChat> imChatList = this.selectByExample(example);

        List<ImChatVO> chatVOList = new ArrayList<>();
        for (ImChat imChat : imChatList) {
            ImChatVO imChatVO = new ImChatVO();
            BeanUtils.copyProperties(imChat, imChatVO);

            String receiver = imChat.getReceiver();
            if (imChat.getReceiver().equals(sender)) {
                receiver = imChat.getSender();
            }

            //获取用户信息
            String senderMsgKey = RedisConstant.getRecentMsgKey(sender, receiver);
            Object o = redisTemplate.opsForHash().get(senderMsgKey, RedisConstant.RECENT_RECEIVER_KEY);
            ImUser imUser = JSON.parseObject(String.valueOf(o), ImUser.class);
            if (imUser != null) {
                imChatVO.setNickname(imUser.getNickname());
                imChatVO.setHeadImg(imUser.getHeadImg());
            }

            //获取未读消息
            Integer count = this.getUnreadCount(sender, receiver);
            imChatVO.setUnReadCount(count);
            totalUnRead += count;

            chatVOList.add(imChatVO);
        }

        result.put("totalUnRead", totalUnRead);
        result.put("data", chatVOList);
        return result;
    }

    @Override
    public Integer getUnreadCount(String sender, String receiver) {
        Example example = new Example(ImChat.class);
        example.createCriteria().andEqualTo("receiver", sender)
                .andEqualTo("sender", receiver)
                .andEqualTo("sign", ImChatConstant.SignType.NO.getId());
        return this.selectCountByExample(example);
    }

    @Override
    public PageInfo<ImChatVO> queryChatList(ImChatListDTO imChatListDTO) {
        String sender = imChatListDTO.getSender();
        String receiver = imChatListDTO.getReceiver();
        ImUser imUserSender = imUserService.selectByPrimaryKey(sender);
        ImUser imUserReceiver = imUserService.selectByPrimaryKey(receiver);
        if (imUserSender == null || imUserReceiver == null) {
            log.error("--->用户找不到,sender={},receiver={}", sender, receiver);
            log.error("--->用户找不到,imUserSender={},imUserReceiver={}", imUserSender, imUserReceiver);
            throw new BusinessException(MsgCode.NOT_FOUNT, "用户找不到");
        }

        List<String> userIds = Arrays.asList(sender, receiver);

        Example example = new Example(ImChat.class);
        example.orderBy("createTime").desc();
        example.createCriteria()
                .andIn("sender", userIds)
                .andIn("receiver", userIds);
        Page<ImChat> page = PageHelper.startPage(imChatListDTO.getPageNum(), imChatListDTO.getPageSize(), true, false, false);
        List<ImChat> imChatList = selectByExample(example);

        //更新签收状态
        if (imChatListDTO.getIsRead()) {
            updateSign(imChatListDTO, imChatList);
        }

        ArrayList<ImChatVO> voArrayList = new ArrayList<>();
        imChatList.forEach(imChat -> {
            ImChatVO imChatVO = new ImChatVO();
            BeanUtils.copyProperties(imChat, imChatVO);
            if (imChat.getSender().equals(imUserSender.getId())) {
                imChatVO.setSenderUser(imUserSender);
            } else {
                imChatVO.setSenderUser(imUserReceiver);
            }
            if (imChat.getReceiver().equals(imUserReceiver.getId())) {
                imChatVO.setReceiverUser(imUserReceiver);
            } else {
                imChatVO.setReceiverUser(imUserSender);
            }
            voArrayList.add(imChatVO);
        });
        if (imChatListDTO.getPageNum() == 1) {
            Collections.reverse(voArrayList);
        }
        PageInfo<ImChatVO> info = new PageInfo<>(voArrayList);
        info.setTotal(page.getTotal());
        return info;
    }

    /**
     * 更新签收状态
     *
     * @param imChatList
     */
    private void updateSign(ImChatListDTO imChatListDTO, List<ImChat> imChatList) {
        if (imChatList == null || imChatList.size() == 0) {
            return;
        }

        Set<String> ids = new HashSet<>();
        for (ImChat imChat : imChatList) {
            if (imChat.getSender().equals(imChatListDTO.getReceiver())
                    && imChat.getReceiver().equals(imChatListDTO.getSender())
                    && ImChatConstant.SignType.NO.getId().equals(imChat.getSign())) {
                ids.add(imChat.getId());
            }
        }

        log.info("------>签收ids={}", ids);
        if (ids == null || ids.isEmpty()) {
            return;
        }

        Example updateExample = new Example(ImChat.class);
        updateExample.createCriteria()
                .andIn("id", ids);
        ImChat imChat = new ImChat().setSign(ImChatConstant.SignType.YES.getId());
        this.updateByExampleSelective(imChat, updateExample);
    }
}